/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include "topology/device_topo.h"
#include "topology/root_topo_object.h"
#include <mc/exception.h>
#include <mc/filesystem.h>
#include <set>
#include <algorithm>
#include <vector>

namespace devmon {


void device_topo::init(mc::engine::service* service) {
    m_service = service;
}

// 创建节点信息对象 - 这里可以使用 make_shared
topo_node_info_ptr device_topo::create_node_info(const std::string& object_name,
                                                 const std::string& position,
                                                 const mc::dict&    objects) {
    mc::mutable_dict csr_object;
    if (objects.contains(object_name)) {
        csr_object = objects[object_name].as<mc::dict>();
    }
    std::string device_type = object_name.substr(0, object_name.find_first_of("_"));

    // 使用 make_shared 创建辅助对象 - 性能更优
    return std::make_shared<topo_node_info>(object_name, position, device_type, csr_object);
}

// 获取父对象
mc::engine::abstract_object*
device_topo::get_parent_object(mc::shared_ptr<mc::engine::abstract_object> previous_object) {
    if (previous_object) {
        return previous_object.get();
    }

    auto& table      = m_service->get_object_table();
    auto  parent_obj = table.find_object(mc::engine::by_object_name::field == "DevTopology");
    return parent_obj ? static_cast<mc::engine::abstract_object*>(parent_obj.get()) : nullptr;
}

mc::shared_ptr<mc::engine::abstract_object>
device_topo::create_topo_object(const topo_node_info_ptr&                   node_info,
                                mc::shared_ptr<mc::engine::abstract_object> previous_object) {
    try {
        auto& drv = device_driver_factory::get_instance().get_device_driver(node_info->device_type);
        auto& device = drv.get_device(node_info->device_type);
        std::string dev_name = node_info->name + "_dev";
        auto device_object = static_cast<mc::engine::abstract_object*>(
            device.ctor(m_service, dev_name.c_str()));
        if (!device_object) {
            elog("create device object failed: ${name}", ("name", node_info->name));
            return nullptr;
        }
        auto parent = get_parent_object(previous_object);
        if (!parent) {
            elog("get parent object failed for device: ${name}", ("name", node_info->name));
            return nullptr;
        }

        device_object->set_parent(parent);
        device_object->set_position(node_info->position);

        auto     mutable_csr = const_cast<mc::dict*>(&node_info->config_data);
        mc::dict conn_config{};
        device.init(device_object, mutable_csr, &conn_config);

        // 注册对象到 engine，然后使用 shared_from_this() 获取智能指针
        m_service->register_object(device_object);
        object_group_data::get_instance().save_device_object(device_object, node_info->position,
                                                             node_info->name);
        auto device_ptr = device_object->shared_from_this();

        ilog("create device success: ${name}", ("name", node_info->name));
        return device_ptr;

    } catch (const mc::invalid_arg_exception& e) {
        elog("device driver not found: ${device_name} for object: ${object_name}",
             ("device_name", node_info->device_type)("object_name", node_info->name));
        return nullptr;
    } catch (const std::exception& e) {
        elog("create device failed: ${name}, error: ${error}",
             ("name", node_info->name)("error", e.what()));
        return nullptr;
    }
}

// 缓存管理器 - 使用 std::shared_ptr 因为它是普通类
class node_cache_manager {
public:
    using cache_map = std::map<std::string, mc::shared_ptr<mc::engine::abstract_object>>;

    // 使用 std::make_shared 创建缓存管理器实例
    static std::shared_ptr<node_cache_manager> create() {
        return std::make_shared<node_cache_manager>();
    }

    mc::shared_ptr<mc::engine::abstract_object> get_cached_node(const std::string& node_name) {
        auto it = m_cache.find(node_name);
        return (it != m_cache.end()) ? it->second : nullptr;
    }

    void cache_node(const std::string&                          node_name,
                    mc::shared_ptr<mc::engine::abstract_object> node) {
        m_cache[node_name] = node;
    }

private:
    cache_map m_cache;
};

mc::shared_ptr<mc::engine::abstract_object> device_topo::get_or_create_node(
    const topo_node_info_ptr&                                           node_info,
    mc::shared_ptr<mc::engine::abstract_object>                         previous_object,
    std::map<std::string, mc::shared_ptr<mc::engine::abstract_object>>& node_map) {
    // 检查缓存
    auto it = node_map.find(node_info->name);
    if (it != node_map.end()) {
        auto cached_node = it->second;
        if (cached_node != nullptr) {
            object_group_data::get_instance().save_device_object(cached_node.get(),
                                                                 node_info->position,
                                                                 node_info->name);
        }
        return cached_node;
    }

    // 检查是否已在 engine 中存在
    // 注意：create_topo_object 创建的对象名称是 node_info->name + "_dev"
    // 所以查找时应该优先查找 "_dev" 后缀的名称
    auto& table = m_service->get_object_table();

    // 优先查找 "_dev" 后缀的名称（因为 create_topo_object 创建的对象名称是 name + "_dev"）
    std::string dev_name = node_info->name + "_dev";
    auto existing_obj = table.find_object(mc::engine::by_object_name::field == dev_name);

    // 如果找不到，再尝试用原始名称查找（可能有些对象没有 "_dev" 后缀）
    if (!existing_obj) {
        existing_obj = table.find_object(mc::engine::by_object_name::field == node_info->name);
    }

    if (existing_obj) {
        // 需要将 mc::core::object_base* 转换为 mc::engine::abstract_object*
        auto* abstract_obj        = static_cast<mc::engine::abstract_object*>(existing_obj.get());
        auto  node_ptr            = abstract_obj->shared_from_this();
        node_map[node_info->name] = node_ptr;
        object_group_data::get_instance().save_device_object(abstract_obj, node_info->position,
                                                             node_info->name);
        return node_ptr;
    }

    // 创建新对象
    auto node_ptr = create_topo_object(node_info, previous_object);
    if (node_ptr) {
        node_map[node_info->name] = node_ptr;
    }
    return node_ptr;
}

// 模板函数：查找现有设备对象
template <typename T>
std::shared_ptr<T> device_topo::find_existing_device_object(const std::string& object_name) {
    auto& device_obj_manager = dev::device_manager::get_instance();

    if constexpr (std::is_same_v<T, dev::bus_base>) {
        auto bus_obj = device_obj_manager.find_object(object_name, dev::object_type::bus);
        if (std::holds_alternative<std::shared_ptr<dev::bus_base>>(bus_obj)) {
            return std::get<std::shared_ptr<dev::bus_base>>(bus_obj);
        }
    } else if constexpr (std::is_same_v<T, dev::chip_base>) {
        auto chip_obj = device_obj_manager.find_object(object_name, dev::object_type::chip);
        if (std::holds_alternative<std::shared_ptr<dev::chip_base>>(chip_obj)) {
            return std::get<std::shared_ptr<dev::chip_base>>(chip_obj);
        }
    }

    return nullptr;
}

// 模板函数：创建新的设备对象
template <typename T>
std::shared_ptr<T> device_topo::create_new_device_object(const topo_node_info_ptr& node_info) {
    auto& device_obj_manager = dev::device_manager::get_instance();

    // 创建 mutable_dict 以满足 Manager 库接口需求
    mc::mutable_dict mutable_config_data = node_info->config_data;
    if (mutable_config_data.empty()) {
        ilog("object data is empty for object: ${object_name}", ("object_name", node_info->name));
        return nullptr;
    }
    mutable_config_data["object_name"] = node_info->name;

    if constexpr (std::is_same_v<T, dev::bus_base>) {
        auto bus_obj = device_obj_manager.create_bus(node_info->name, node_info->device_type,
                                                     mutable_config_data);
        if (!bus_obj) {
            elog("create bus object failed: ${bus_name}", ("bus_name", node_info->name));
            return nullptr;
        }
        return bus_obj;
    } else if constexpr (std::is_same_v<T, dev::chip_base>) {
        auto chip_obj = device_obj_manager.create_chip(node_info->name, node_info->device_type,
                                                       mutable_config_data);
        if (!chip_obj) {
            elog("create chip object failed: ${chip_name}", ("chip_name", node_info->name));
            return nullptr;
        }
        return chip_obj;
    }

    return nullptr;
}

std::tuple<std::shared_ptr<dev::bus_base>, mc::shared_ptr<mc::engine::abstract_object>>
device_topo::get_bus_node(const topo_node_info_ptr&                   node_info,
                          mc::shared_ptr<mc::engine::abstract_object> previous_object) {
    // 早期返回：检查输入参数
    if (!node_info) {
        elog("node_info is null");
        return std::make_tuple(nullptr, nullptr);
    }

    // 尝试查找现有总线对象
    auto bus_obj = find_existing_device_object<dev::bus_base>(node_info->name);

    if (!bus_obj) {
        // 创建新的总线对象
        bus_obj = create_new_device_object<dev::bus_base>(node_info);
    }

    if (bus_obj) {
        auto bus_node = get_or_create_node(node_info, previous_object, m_bus_map);
        return std::make_tuple(bus_obj, bus_node);
    }

    return std::make_tuple(nullptr, nullptr);
}

std::tuple<std::shared_ptr<dev::chip_base>, mc::shared_ptr<mc::engine::abstract_object>>
device_topo::get_chip_node(const topo_node_info_ptr&                   node_info,
                           mc::shared_ptr<mc::engine::abstract_object> previous_object) {
    // 早期返回：检查输入参数
    if (!node_info) {
        elog("node_info is null");
        return std::make_tuple(nullptr, nullptr);
    }

    // 尝试查找现有芯片对象
    auto chip_obj = find_existing_device_object<dev::chip_base>(node_info->name);

    if (!chip_obj) {
        // 创建新的芯片对象
        chip_obj = create_new_device_object<dev::chip_base>(node_info);
    }

    if (chip_obj) {
        auto chip_node = get_or_create_node(node_info, previous_object, m_chip_map);
        return std::make_tuple(chip_obj, chip_node);
    }

    return std::make_tuple(nullptr, nullptr);
}

// 获取总线下的芯片列表（统一处理多种数据格式）
mc::variants device_topo::get_chips_from_bus(const std::string& bus_name,
                                             const mc::dict&    topology) {
    if (!topology.contains(bus_name)) {
        return mc::variants{};
    }

    const auto& bus_data = topology[bus_name];

    // dict 格式：Bus -> {Chips: [chip1, chip2]}
    if (bus_data.is_dict() && bus_data.contains("Chips") && bus_data["Chips"].is_array()) {
        return bus_data["Chips"].get_array();
    }

    // array 格式：Bus -> [chip1, chip2]
    if (bus_data.is_array()) {
        return bus_data.get_array();
    }

    return mc::variants{};
}

// 获取芯片下的总线列表
mc::variants device_topo::get_buses_from_chip(const std::string& chip_name,
                                              const mc::dict&    topology) {
    if (!topology.contains(chip_name)) {
        return mc::variants{};
    }

    const auto& chip_data = topology[chip_name];

    if (chip_data.is_dict() && chip_data.contains("Buses") && chip_data["Buses"].is_array()) {
        return chip_data["Buses"].get_array();
    }

    if (chip_data.is_array()) {
        return chip_data.get_array();
    }

    return mc::variants{};
}

// 从拓扑数据中提取总线列表
mc::variants device_topo::extract_buses_from_topology(const mc::dict& topology) {
    if (!topology.contains("Anchor")) {
        elog("topology missing Anchor field");
        return mc::variants{};
    }

    const auto& anchor = topology["Anchor"];

    // 处理dict格式：{"Anchor": {"Buses": [...]}}
    if (anchor.is_dict()) {
        const auto& anchor_dict = anchor.as_dict();
        if (!anchor_dict.contains("Buses")) {
            elog("invalid Anchor format, missing Buses field");
            return mc::variants{};
        }

        const auto& buses = anchor_dict["Buses"];
        if (!buses.is_array()) {
            elog("invalid Anchor.Buses format, expected array");
            return mc::variants{};
        }

        return buses.get_array();
    }

    // 处理数组格式：{"Anchor": [...]}（向后兼容）
    if (anchor.is_array()) {
        return anchor.get_array();
    }

    elog("invalid Anchor format, expected dict with Buses field or array");
    return mc::variants{};
}

void device_topo::process_buses(const std::string& position, const mc::dict& topology,
                                const mc::dict& objects_data, const chip_pair& parent_chip,
                                const mc::variants& buses_override) {
    // 确定要处理的总线列表
    mc::variants buses_to_process;
    if (buses_override.empty()) {
        // 如果没有提供总线列表，从拓扑数据中提取
        buses_to_process = extract_buses_from_topology(topology);
        if (buses_to_process.empty()) {
            return; // 没有总线可处理
        }
    } else {
        // 使用提供的总线列表
        buses_to_process = buses_override;
    }

    // 严格验证总线列表中的数据类型 - 如果有非字符串类型，停止解析
    for (const auto& bus_name_var : buses_to_process) {
        if (!bus_name_var.is_string()) {
            elog("invalid bus entry in topology: expected string, got ${type} - stopping topology "
                 "parsing",
                 ("type", bus_name_var.get_type_name()));
            return; // 立即停止解析，不处理任何总线
        }
    }

    // 创建本地副本以便在需要时修改
    chip_pair current_parent_chip = parent_chip;

    // 处理总线列表（只有在所有条目都是字符串类型时才会执行到这里）
    for (const auto& bus_name_var : buses_to_process) {
        const std::string bus_name = bus_name_var.as_string();

        // 创建topo_node_info
        auto node_info           = create_node_info(bus_name, position, objects_data);
        auto [bus_obj, bus_node] = get_bus_node(node_info, current_parent_chip.second);
        
        if (!bus_node || !bus_obj) {
            wlog("failed to create or get bus node: ${bus_name}", ("bus_name", bus_name));
            continue;
        }

        if (m_device_map.find(position) != m_device_map.end() && m_device_map[position] != nullptr) {
            bus_node->set_parent(m_device_map[position].get());
        }
        
        // 如果父芯片为空，尝试从现有总线对象中获取
        if (!current_parent_chip.first) {
            auto pre_bus_obj = find_existing_device_object<dev::bus_base>(bus_name);
            if (pre_bus_obj) {
                current_parent_chip.first = pre_bus_obj->get_left_chip();
            }
        }

        // 设置总线对象的关系（节点关系已在 get_bus_node 中设置）
        if (current_parent_chip.first) {
            bus_obj->set_left_chip(current_parent_chip.first);
        }

        // 处理总线下的芯片
        const auto chips = get_chips_from_bus(bus_name, topology);
        if (!chips.empty()) {
            process_chips(position, chips, topology, objects_data, {bus_obj, bus_node},
                          current_parent_chip);
        }
    }
}

void device_topo::process_chips(const std::string& position, const mc::variants& chips,
                                const mc::dict& topology, const mc::dict& objects_data,
                                const bus_pair& parent_bus, const chip_pair& parent_chip) {
    // 严格验证芯片列表中的数据类型 - 如果有非字符串类型，停止解析
    for (const auto& chip_name_var : chips) {
        if (!chip_name_var.is_string()) {
            elog("invalid chip entry in topology: expected string, got ${type} - stopping chip "
                 "processing",
                 ("type", chip_name_var.get_type_name()));
            return; // 立即停止处理，不处理任何芯片
        }
    }

    // 处理芯片列表（只有在所有条目都是字符串类型时才会执行到这里）
    for (const auto& chip_name_var : chips) {
        const std::string chip_name = chip_name_var.as_string();

        // 创建topo_node_info
        auto node_info             = create_node_info(chip_name, position, objects_data);
        auto [chip_obj, chip_node] = get_chip_node(node_info, parent_bus.second);
        if (!chip_node || !chip_obj) {
            wlog("failed to create or get chip node: ${chip_name}", ("chip_name", chip_name));
            continue;
        }

        // 设置芯片对象的关系（节点关系已在 get_chip_node 中设置）
        chip_obj->set_left_bus(parent_bus.first);
        if (parent_chip.first) {
            chip_obj->set_left_chip(parent_chip.first);
            chip_obj->set_host_bus(parent_chip.first->get_host_bus());
        } else {
            chip_obj->set_host_bus(parent_bus.first);
        }

        // 处理芯片下的子总线（递归处理）
        const auto chip_buses = get_buses_from_chip(chip_name, topology);
        if (!chip_buses.empty()) {
            process_buses(position, topology, objects_data, {chip_obj, chip_node}, chip_buses);
        }
    }
}

bool device_topo::add_topology(const mc::dict& topology, const mc::dict& objects,
                               const std::string& position) {
    std::lock_guard<std::mutex> lock(m_topology_mutex);
    
    try {
        std::shared_ptr<mc::engine::service> serivce_ptr(m_service,
                                                         [](mc::engine::service* service) {
                                                         });
        if (func_collection::get_instance().get(position).empty()) {
            mc::mutable_dict functions;
            func_collection::get_instance().add(position, serivce_ptr, functions);
        }
        // 顶层调用时没有上级芯片，使用默认参数
        process_buses(position, topology, objects, {nullptr, nullptr}, mc::variants{});
        nlog("add topology success for position: ${position}", ("position", position));
        return true;
    } catch (const std::exception& e) {
        elog("add topology failed for position: ${position}, error: ${error}",
             ("position", position)("error", e.what()));
        return false;
    }
}

void device_topo::add_device_object(const std::string&                          position,
                                    mc::shared_ptr<mc::engine::abstract_object> device_object) {
    m_device_map[position] = device_object;
}

void device_topo::remove_device_object(const std::string& position) {
    auto it = m_device_map.find(position);
    if (it == m_device_map.end()) {
        return;
    }
    auto device_object = it->second;
    if (device_object && m_service) {
        m_service->unregister_object(device_object);
    }
    m_device_map.erase(it);
}

mc::shared_ptr<mc::engine::abstract_object> device_topo::get_device_object(const std::string& position) {
    auto it = m_device_map.find(position);
    if (it != m_device_map.end()) {
        return it->second;
    }
    return nullptr;
}

std::string device_topo::remove_dev_suffix(const std::string& name) const {
    std::string result = name;
    auto suffix_pos = result.rfind("_dev");
    if (suffix_pos != std::string::npos && suffix_pos + 4 == result.length()) { // 4代表"_dev" 后缀长度
        result.erase(suffix_pos);
    }
    return result;
}

std::string device_topo::get_display_name(mc::engine::abstract_object* object) const {
    if (!object) {
        return "Unknown";
    }

    std::string object_name = remove_dev_suffix(std::string(object->get_object_name()));
    
    // 如果对象有 ChannelId 属性，使用 Channel_X 作为显示名
    try {
        if (object->has_property("ChannelId")) {
            auto channel_id_var = object->get_property("ChannelId");
            if (!channel_id_var.is_null()) {
                uint8_t channel_id = channel_id_var.as<uint8_t>();
                return "Channel_" + std::to_string(channel_id);
            }
        }
    } catch (const std::exception& e) {
        wlog("Failed to get ChannelId for object ${name}: ${error}",
             ("name", object_name)("error", e.what()));
    }
    return object_name;
}

void device_topo::dump_topology_node(std::string& content, mc::engine::abstract_object* object, int depth,
                                     std::set<std::string>& visited,
                                     const std::string& prefix, bool is_last) const {
    if (!object) {
        return;
    }
    
    std::string object_name(object->get_object_name());
    if (visited.count(object_name) > 0) {
        return;
    }
    visited.insert(object_name);

    std::string display_name = get_display_name(object);

    // 根节点单独处理
    if (depth == 0) {
        content += display_name;
        content += "\n";
    } else {
        // 非根节点：使用树形字符
        content += prefix;
        if (is_last) {
            content += "└─";
        } else {
            content += "├─";
        }
        content += display_name;
        content += "\n";
    }

    const auto& managed_objects = object->get_managed_objects();
    if (managed_objects.empty()) {
        return;
    }

    std::vector<std::pair<std::string_view, mc::engine::abstract_object*>> children;
    children.reserve(managed_objects.size());
    for (const auto& entry : managed_objects) {
        children.emplace_back(entry.first, entry.second);
    }
    std::sort(children.begin(), children.end(),
                [](const auto& lhs, const auto& rhs) { return lhs.first < rhs.first; });

    // 递归处理子节点
    for (size_t i = 0; i < children.size(); ++i) {
        bool child_is_last = (i == children.size() - 1);
        std::string child_prefix = prefix;
        
        if (depth > 0) {
            // 根据当前节点是否是最后一个，决定子节点的前缀
            if (is_last) {
                child_prefix += " ";
            } else {
                child_prefix += "│ ";
            }
        }
        dump_topology_node(content, children[i].second, depth + 1, visited, child_prefix, child_is_last);
    }
}

void device_topo::dump_topology(const std::string& directory_path) const {
    std::lock_guard<std::mutex> lock(m_topology_mutex);
    if (!m_service) {
        elog("service is not initialized, skip dumping topology");
        return;
    }

    // 验证目录路径是否存在且是合法目录
    if (!mc::filesystem::is_directory(directory_path)) {
        elog("invalid directory path: ${path}", ("path", directory_path));
        return;
    }
    std::string file_path = directory_path + '/' + "topology.txt";
    auto& table   = m_service->get_object_table();
    auto  root_it = table.find_object(mc::engine::by_object_name::field == "DevTopology");
    if (!root_it) {
        elog("root topology object missing, dumping aborted");
        return;
    }

    std::set<std::string> visited;
    auto* root_obj = static_cast<mc::engine::abstract_object*>(root_it.get());
    
    // 拓扑内容字符串
    std::string content;

    nlog("Start dump topology to topology.txt");
    const auto& managed_objects = root_obj->get_managed_objects();
    if (!managed_objects.empty()) {
        std::vector<std::pair<std::string_view, mc::engine::abstract_object*>> children;
        children.reserve(managed_objects.size());
        for (const auto& entry : managed_objects) {
            children.emplace_back(entry.first, entry.second);
        }
        std::sort(children.begin(), children.end(),
                    [](const auto& lhs, const auto& rhs) { return lhs.first < rhs.first; });
        
        // 遍历所有子节点，每个都作为根节点显示（depth=0）
        for (size_t i = 0; i < children.size(); ++i) {
            bool is_last = (i == children.size() - 1);
            dump_topology_node(content, children[i].second, 0, visited, "", is_last);
            // 在多个根节点之间添加空行分隔（最后一个除外）
            if (!is_last) {
                content += "\n";
            }
        }
    }
    
    // 使用 filesystem::write_file 一次性写入文件
    if (!mc::filesystem::write_file(file_path, content)) {
        elog("failed to write topology file: topology.txt");
        return;
    }

    nlog("dump topology to topology.txt successfully");
    return;
}
} // namespace devmon

MC_REFLECT(devmon::root_topo_object, ((m_root_interface, "root_topo")))